package edu.washington.ling.syntric.io;

import java.util.regex.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import edu.washington.ling.syntric.struct.rule.*;
import edu.washington.ling.syntric.struct.tree.Node;
import edu.washington.ling.syntric.struct.tree.Token;


public class RuleReader {
	private final Pattern uniRuleRE = Pattern.compile("^(\\d+)\\s\\[(.+?)\\]\\s\\[(.+?)\\]$");
	private final Pattern biRuleRE = Pattern.compile("^(\\d+)\\s\\[(.+?)\\]\\s\\[(.+?)\\]\\s(\\?|0|1)\\s\\((.+?)\\)$");
	private final Pattern biPSPatternRE = Pattern.compile("^(.+?)\\s\\((.+?)\\s(.+?)\\)$");
	private final Pattern tokenRE = Pattern.compile("^(.+) \\<fs (.*?)\\>$");
	
	private Token readToken(String tokenStr) {
		Matcher m = tokenRE.matcher(tokenStr);
		Token t = null;
		if (m.matches()) {
			t = new Token();
			t.setTag(m.group(1));
			String featStr = m.group(2);
			if (featStr.length() > 0) {
				String[] fvStrs = featStr.split(" ");
				for (String fvStr: fvStrs) {
					String[] fvElems = fvStr.split("=");
					t.setFeature(fvElems[0], fvElems[1]);
				}
			}
		}
		return t;
	}
	
	private Node readNode(String nodeStr) {
		Node n = new Node();
		n.setLabel(nodeStr);
		return n;
	}
	
	private UniDSPattern readUnaryDSPattern(String dsStr) {
		Token dsToken = readToken(dsStr);
		return new UniDSPattern(dsToken);
	}
	
	private UniPSPattern readUnaryPSPattern(String psStr) {
		String[] nodeStrs = psStr.split(" ");
		ArrayList<Node> psNodes = new ArrayList<Node>();
		for (String nodeStr: nodeStrs) {
			psNodes.add(readNode(nodeStr));
		}
		return new UniPSPattern(psNodes);
	}
	
	private BiDSPattern readBinaryDSPattern(String dsChildStr, String dsParentStr, String orderStr) {
		Token dsChild = readToken(dsChildStr);
		Token dsParent = readToken(dsParentStr);
		BiDSPattern dsPatt = new BiDSPattern(dsChild, dsParent);
		if (orderStr.equals("0")) {
			dsPatt.setHeadFinal(false);
		}
		else if (orderStr.equals("1")) {
			dsPatt.setHeadFinal(true);
		}
		return dsPatt;
	}
	
	private BiPSPattern readBinaryPSPattern(String pattStr) {
		Matcher m = biPSPatternRE.matcher(pattStr);
		BiPSPattern psPatt = null;
		if (m.matches()) {
			List<Node> rootElems = new LinkedList<Node>();
			String[] rootStrs = m.group(1).split(" ");
			for (String rootStr: rootStrs) {
				rootElems.add(readNode(rootStr));
			}
			Node psDepChild = readNode(m.group(2));
			Node psHeadChild = readNode(m.group(3));
			psPatt = new BiPSPattern(rootElems, psDepChild, psHeadChild);
		}
		return psPatt;
	}
	
	public UniRule readUnaryRule(String ruleString){
		UniRule rule = null;
		Matcher m = uniRuleRE.matcher(ruleString);
		if (m.matches()) {
			UniDSPattern dsPattern = readUnaryDSPattern(m.group(2));
			UniPSPattern psPattern = readUnaryPSPattern(m.group(3));
			rule = new UniRule(dsPattern, psPattern);
		} else {
			//throw an error.
		}
		return rule;
	}
	
	public BiRule readBinaryRule(String ruleString) {
		BiRule rule = null;
		Matcher m = biRuleRE.matcher(ruleString);
		if (m.matches()) {
			BiDSPattern dsPattern = readBinaryDSPattern(m.group(2), m.group(3), m.group(4));
			BiPSPattern psPattern = readBinaryPSPattern(m.group(5));
			rule = new BiRule(dsPattern, psPattern);
		} else {
			//throw an error.
		}
		return rule;
	}
	

}
